using System.Runtime.CompilerServices;
using SoftFloat;

namespace Jitter2.LinearMath
{
    public partial struct NVector3
    {
        public readonly NVector3 Normalized => Normalize(this);

        /// <summary>
        /// Gets the up vector (0,1,0).
        /// </summary>
        public static NVector3 Up
        {
            get
            {
                return new NVector3()
                {
                    X = 0,
                    Y = 1,
                    Z = 0
                };
            }
        }

        /// <summary>
        /// Gets the down vector (0,-1,0).
        /// </summary>
        public static NVector3 Down
        {
            get
            {
                return new NVector3()
                {
                    X = 0,
                    Y = -1,
                    Z = 0
                };
            }
        }

        /// <summary>
        /// Gets the right vector (1,0,0).
        /// </summary>
        public static NVector3 Right
        {
            get
            {
                return new NVector3()
                {
                    X = 1,
                    Y = 0,
                    Z = 0
                };
            }
        }

        /// <summary>
        /// Gets the left vector (-1,0,0).
        /// </summary>
        public static NVector3 Left
        {
            get
            {
                return new NVector3()
                {
                    X = -1,
                    Y = 0,
                    Z = 0
                };
            }
        }

        /// <summary>
        /// Gets the forward vector (0,0,-1).
        /// </summary>
        public static NVector3 Forward
        {
            get
            {
                return new NVector3()
                {
                    X = 0,
                    Y = 0,
                    Z = -1
                };
            }
        }

        /// <summary>
        /// Gets the back vector (0,0,1).
        /// </summary>
        public static NVector3 Backward
        {
            get
            {
                return new NVector3()
                {
                    X = 0,
                    Y = 0,
                    Z = 1
                };
            }
        }

        public static void Divide(ref NVector3 v, sfloat divisor, out NVector3 result)
        {
            sfloat inverse = 1 / divisor;
            result.X = v.X * inverse;
            result.Y = v.Y * inverse;
            result.Z = v.Z * inverse;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static NVector3 Normalize(NVector3 value)
        {
            sfloat num = Magnitude(value);
            if (num > 1E-05f)
            {
                return value / num;
            }

            return Zero;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static sfloat Magnitude(NVector3 vector)
        {
            return libm.Sqrt(vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static sfloat SqrMagnitude(NVector3 vector)
        {
            return vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static NVector3 operator /(NVector3 a, sfloat d)
        {
            return new NVector3(a.X / d, a.Y / d, a.Z / d);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static sfloat Distance(NVector3 a, NVector3 b)
        {
            sfloat num = a.X - b.X;
            sfloat num2 = a.Y - b.Y;
            sfloat num3 = a.Z - b.Z;
            return libm.Sqrt(num * num + num2 * num2 + num3 * num3);
        }

#if UNITY_STANDALONE || UNITY_ANDROID || UNITY_IOS || UNITY_WSA || UNITY_WEBGL
        public static bool operator ==(UnityEngine.Vector3 lhs, NVector3 rhs)
        {
            return (lhs - rhs).sqrMagnitude < (float)9.9999994E-11f;
        }

        public static bool operator !=(UnityEngine.Vector3 lhs, NVector3 rhs)
        {
            return !(lhs == rhs);
        }

        public static implicit operator UnityEngine.Vector3(NVector3 v)
        {
            return new UnityEngine.Vector3(-v.X, v.Y, v.Z);
        }

        public static implicit operator NVector3(UnityEngine.Vector3 v)
        {
            return new NVector3(-v.x, v.y, v.z);
        }
#endif
    }
}